学习周报-2025-03-16
JavaScript的数字精度问题
toFixed的结果可能会欺骗你【渡一教育】_哔哩哔哩_bilibili
先看下面的代码:
ts
1.45.toFixed(1); // 1.4
2.45.toFixed(1); // 2.5
问题的原因是 JavaScript 的存储和操作各种数字都是基于二进制的,而二进制无法准确表示小数。
存储精度问题
可以使用 .toString(2)
方法获取一个数字的二进制表示,这时会发现大多数小数的二进制表示是无限重复的。
存储时,小数部分会被截断。如果截断位置是 0,结果会变小,如果截断位置是 1,结果会变大。
可以使用 .toPrecision()
方法将数字转换为指定精度的字符串,这样就可以清楚地看到问题。
例如:
ts
console.log(1.45.toPrecision(50)); // '1.4499999999999999555910790149937383830547332763672'
console.log(2.45.toPrecision(50)); // '2.4500000000000001776356839400250464677810668945313'
这里可以看到,1.45 转换后结果变小,2.45 转换后结果变大。
操作精度问题
当进行操作时,使用二进制进行操作,所以也可能存在精度问题。
例如:
ts
console.log(0.1 + 0.2); // 0.30000000000000004
显示精度问题
虽然存储不准确,但浏览器会进行近似处理,所以在控制台中显示是正确的。
ts
console.log(0.3) // 0.3
console.log(0.3.toPrecision(50)) // '0.29999999999999998889776975374843459576368331909180'
console.log(0.29999999999999998889776975374843459576368331909180) // 0.3
console.log(0.3 === 0.29999999999999998889776975374843459576368331909180) // true
基于 toFixed()
方法的 1.45 和 2.45 精度问题
ts
console.log(1.45.toString(2)) // 1.0111001100110011001100110011001100110011001100110011
console.log(1.45.toPrecision(50)); // '1.4499999999999999555910790149937383830547332763672'
console.log(2.45.toString(2)) // 10.01110011001100110011001100110011001100110011001101
console.log(2.45.toPrecision(50)); // '2.4500000000000001776356839400250464677810668945313'
因为 2.45 的整数部分是 10,占据 2 位,而 1.45 的整数部分是 1,只占据 1 位,所以虽然理论上 1.45 和 2.45 的小数部分是相同的,但在实际存储时,2.45 的存储位数会更少,导致四舍五入后的结果不同。